//
// Created by zpf on 2023/5/15.
//
#include "watcher-private.h"
#include "statusnotifierwatcheradaptor.h"
#include "statusnotifieriteminterface.h"
#include "watcher.h"

WatcherPrivate::WatcherPrivate(QObject *parent) : QObject(parent)
{
    new StatusNotifierWatcherAdaptor(this);
    QDBusConnection dbus = QDBusConnection::sessionBus();
    dbus.registerObject(QStringLiteral("/StatusNotifierWatcher"), this);
    dbus.registerService(QStringLiteral("org.kde.StatusNotifierWatcher"));
    m_serviceWatcher = new QDBusServiceWatcher(this);
    m_serviceWatcher->setConnection(dbus);
    m_serviceWatcher->setWatchMode(QDBusServiceWatcher::WatchForUnregistration);
    connect(m_serviceWatcher, &QDBusServiceWatcher::serviceUnregistered, this, &WatcherPrivate::serviceUnregistered);
}

WatcherPrivate::~WatcherPrivate()
{
    QDBusConnection dbus = QDBusConnection::sessionBus();
    dbus.unregisterService(QStringLiteral("org.kde.StatusNotifierWatcher"));
}

QStringList WatcherPrivate::RegisteredStatusNotifierItems() const
{
    return m_registeredServices;
}

bool WatcherPrivate::IsStatusNotifierHostRegistered() const
{
//    return !m_statusNotifierHostServices.isEmpty();
    return true;
}

int WatcherPrivate::ProtocolVersion() const
{
    return 0;
}

void WatcherPrivate::RegisterStatusNotifierItem(const QString &service)
{
    QString realService;
    QString path;
    if (service.startsWith(QLatin1Char('/'))) {
        realService = message().service();
        path = service;
    } else {
        realService = service;
        path = QStringLiteral("/StatusNotifierItem");
    }
    QString notifierItemId = realService + path;
    if (m_registeredServices.contains(notifierItemId)) {
        return;
    }
    if (QDBusConnection::sessionBus().interface()->isServiceRegistered(realService).value()) {
        // check if the service has registered a SystemTray object
        org::kde::StatusNotifierItem item(realService, path, QDBusConnection::sessionBus());
        if (item.isValid()) {
            qDebug() << "Registering" << notifierItemId << "to system tray";
            m_serviceWatcher->addWatchedService(realService);
            m_registeredServices.append(notifierItemId);
            Q_EMIT StatusNotifierItemRegistered(notifierItemId);
        }
    }
}

void WatcherPrivate::RegisterStatusNotifierHost(const QString &service)
{
    if (service.contains(QLatin1String("org.kde.StatusNotifierHost-")) && QDBusConnection::sessionBus().interface()->isServiceRegistered(service).value()
        && !m_statusNotifierHostServices.contains(service)) {
        qDebug() << "Registering" << service << "as system tray";
        m_statusNotifierHostServices.insert(service);
        m_serviceWatcher->addWatchedService(service);
        Q_EMIT StatusNotifierHostRegistered();
    }
}

void WatcherPrivate::serviceUnregistered(const QString &service)
{
    qDebug() << "Service " << service << "unregistered";
    m_serviceWatcher->removeWatchedService(service);

    const QString match = service + QLatin1Char('/');
    QStringList::Iterator it = m_registeredServices.begin();
    while (it != m_registeredServices.end()) {
        if (it->startsWith(match)) {
            QString name = *it;
            it = m_registeredServices.erase(it);
            Q_EMIT StatusNotifierItemUnregistered(name);
        } else {
            ++it;
        }
    }

    if (m_statusNotifierHostServices.contains(service)) {
        m_statusNotifierHostServices.remove(service);
        Q_EMIT StatusNotifierHostUnregistered();
    }
}

Watcher &Watcher::self()
{
    static Watcher self;
    return self;
}

Watcher::Watcher(): d(new WatcherPrivate)
{
}

Watcher::~Watcher()
{
    if(d) {
        delete d;
        d = nullptr;
    }
}
